package com.anji.plus.gaea.export.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.anji.plus.gaea.code.ResponseCode;
import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
import com.anji.plus.gaea.export.vo.ExportOperation;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Created by raodeming on 2021/4/23.
 */

public class GaeaReportPdfUtil {

    /**
     * 记录日志
     */
    protected static Logger logger = LoggerFactory.getLogger(GaeaReportPdfUtil.class);


    public static void pdfExportByFilePath(ExportOperation exportOperation) {
        JSONObject json = JSONObject.parseObject(exportOperation.getJsonStr(), Feature.OrderedField);

        try {
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            //1.new document
            Document document = new Document(PageSize.A4);
            PdfWriter.getInstance(document, new FileOutputStream(exportOperation.getFilePath()));
            //2 open document
            document.open();
            JSONObject rows = json.getJSONObject("rows");
            JSONArray styles = json.getJSONArray("styles");
            JSONObject cols = json.getJSONObject("cols");

            int defaultWidth = 100;
            int defaultHeight = 25;
            rows.remove("len");
            //需要得到最多的列数
            AtomicInteger colSize = new AtomicInteger();
            rows.forEach((row, col) -> {
                JSONObject colJson = JSONObject.parseObject(col.toString(), Feature.OrderedField);
                JSONObject cells = colJson.getJSONObject("cells");
                int size = cells.size();
                if (colSize.get() < size) {
                    colSize.set(size);
                }
            });

            AtomicReference<String> colNumber = new AtomicReference<>("0");
            rows.forEach((row, col) -> colNumber.set(row));
            //3.添加pdf tables colSize.get()表示列数，
            PdfPTable pdfTable = new PdfPTable(colSize.get());
            float[] tableWidthArray = new float[colSize.get()];
            for (int i = 0; i < colSize.get(); i++) {
                if (cols.containsKey(String.valueOf(i))) {
                    Integer width = cols.getJSONObject(String.valueOf(i)).getInteger("width");
                    tableWidthArray[i] = width;
                } else {
                    tableWidthArray[i] = defaultWidth;
                }
            }
            pdfTable.setWidths(tableWidthArray);
            Map<Integer, Set<Integer>> colspanMap = new HashMap<>();
            for (int j = 0; j <= Integer.parseInt(colNumber.get()); j++) {
                if (rows.containsKey(String.valueOf(j))) {
                    JSONObject colJson = rows.getJSONObject(String.valueOf(j));
                    JSONObject cells = colJson.getJSONObject("cells");
                    Integer height = colJson.getInteger("height");

                    for (int i = 0; i < colSize.get(); i++) {
                        boolean flag = true;
                        if (colspanMap.containsKey(j)) {
                            Set<Integer> integer = colspanMap.get(j);
                            if (integer.contains(i)) {
                                flag = false;
                            }
                        }
                        if (flag) {
                            if (cells.containsKey(String.valueOf(i))) {
                                JSONObject cellDetail = cells.getJSONObject(String.valueOf(i));
                                String text = cellDetail.getString("text");
                                //二维码条形码从text中解析
                                JSONObject qrCodeJson = new JSONObject();
                                if (StringUtils.isNotBlank(text) && text.startsWith("{") && text.endsWith("}")) {
                                    //代表text中为对象，不是单纯的text，另外解析
                                    try {
                                        qrCodeJson = cellDetail.getJSONObject("text");
                                    } catch (Exception e) {
                                        qrCodeJson = null;
                                    }
                                    if (null != qrCodeJson
                                            && qrCodeJson.containsKey("type")
                                            && qrCodeJson.containsKey("content")
                                            && qrCodeJson.containsKey("width")
                                            && qrCodeJson.containsKey("height")) {
                                        text = " ";
                                    } else {
                                        qrCodeJson = null;
                                    }

                                }
//                                cellDetail.get
                                Integer style = cellDetail.getInteger("style");
                                JSONArray merge = cellDetail.getJSONArray("merge");
                                PdfPCell pdfCell = new PdfPCell();
                                //合并单元格
                                setMerge(pdfCell, merge, colspanMap, j, i);
                                //单元格内容和样式
                                setStyleAndText(pdfCell, style, styles, text, bfChinese);

                                //行高
                                int heightMerge = 1;
                                if (null != merge) {
                                    heightMerge = merge.getInteger(0) + 1;
                                }
                                pdfCell.setFixedHeight(null == height ? defaultHeight * heightMerge : height);
                                //二维码
                                createImageCell(qrCodeJson, pdfCell);
                                pdfTable.addCell(pdfCell);
                            } else {
                                pdfTable.addCell(createEmptyCell(null == height ? defaultHeight : height));
                            }
                        }

                    }
                } else {
                    pdfTable.addCell(createEmptyCell(defaultHeight));
                }
            }
            document.add(pdfTable);
            //4. 关闭document
            document.close();

        } catch (DocumentException | IOException ex) {
            logger.info("export pdf error", ex);
            throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, ex.getMessage());
        }

    }

    public static void setMerge(PdfPCell pdfCell, JSONArray merge, Map<Integer, Set<Integer>> colspanMap, int j, int i) {
        if (null != merge) {
            int colspan = merge.getInteger(1) + 1;
            int rowspan = merge.getInteger(0);
            pdfCell.setRowspan(rowspan + 1);
            pdfCell.setColspan(colspan);

            if (colspan > 0) {
                Set<Integer> set;
                if (colspanMap.containsKey(j)) {
                    set = colspanMap.get(j);
                } else {
                    set = new HashSet<>();
                }
                for (int i1 = 0; i1 < colspan; i1++) {
                    set.add(i + i1);
                }
                colspanMap.put(j, set);
            }
            if (rowspan > 0) {
                for (int i1 = 1; i1 <= rowspan; i1++) {
                    for (int i2 = 0; i2 < colspan; i2++) {
                        Set<Integer> set;
                        if (colspanMap.containsKey(j + i1)) {
                            set = colspanMap.get(j + i1);
                        } else {
                            set = new HashSet<>();
                        }
                        set.add(i + i2);
                        colspanMap.put(j + i1, set);
                    }
                }
            }
        }
    }


    /**
     * 设置单元格的内容和样式
     *
     * @param pdfCell
     * @param style
     * @param styles
     * @param text
     */
    public static void setStyleAndText(PdfPCell pdfCell, Integer style, JSONArray styles, String text, BaseFont bfChinese) {

        String color = null;
        Integer fontSize = 10;
        boolean italic = false;
        boolean bold = false;
        boolean underline = false;
        boolean strike = false;
        if (null != style) {
            JSONObject styleJson = styles.getJSONObject(style);
            if (styleJson.containsKey("align")) {
                String align = styleJson.getString("align");
                pdfCell.setHorizontalAlignment(getHorizontalAlignment(align));
            }
            if (styleJson.containsKey("valign")) {
                String valign = styleJson.getString("valign");
                pdfCell.setVerticalAlignment(getVerticalAlignment(valign));
            }
            if (styleJson.containsKey("color")) {
                //设置单元格字体颜色
                color = styleJson.getString("color");
            }

            if (styleJson.containsKey("bgcolor")) {
                //设置单元格背景颜色
                String bgcolor = styleJson.getString("bgcolor");
                pdfCell.setBackgroundColor(toColorFromString(bgcolor));
            }
            if (styleJson.containsKey("border")) {
                //设置单元格的边框
                JSONObject border = styleJson.getJSONObject("border");
                if (border.containsKey("bottom")) {
                    JSONArray type = border.getJSONArray("bottom");
                    pdfCell.setBorderWidthBottom(getBorderWidth(type.getString(0)));
                    pdfCell.setBorderColorBottom(toColorFromString(type.getString(1)));
                } else {
                    pdfCell.disableBorderSide(Rectangle.BOTTOM);
                }
                if (border.containsKey("top")) {
                    JSONArray type = border.getJSONArray("top");
                    pdfCell.setBorderWidthTop(getBorderWidth(type.getString(0)));
                    pdfCell.setBorderColorTop(toColorFromString(type.getString(1)));
                } else {
                    pdfCell.disableBorderSide(Rectangle.TOP);
                }

                if (border.containsKey("left")) {
                    JSONArray type = border.getJSONArray("left");
                    pdfCell.setBorderWidthLeft(getBorderWidth(type.getString(0)));
                    pdfCell.setBorderColorLeft(toColorFromString(type.getString(1)));
                } else {
                    pdfCell.disableBorderSide(Rectangle.LEFT);
                }

                if (border.containsKey("right")) {
                    JSONArray type = border.getJSONArray("right");
                    pdfCell.setBorderWidthRight(getBorderWidth(type.getString(0)));
                    pdfCell.setBorderColorRight(toColorFromString(type.getString(1)));
                } else {
                    pdfCell.disableBorderSide(Rectangle.RIGHT);
                }
            } else {
                //不包含边框，默认全部隐藏
                pdfCell.disableBorderSide(Rectangle.LISTITEM);
            }
            if (styleJson.containsKey("font")) {
                JSONObject font = styleJson.getJSONObject("font");
                if (font.containsKey("size")) {
                    fontSize = font.getInteger("size");
                }
                if (font.containsKey("italic")) {
                    italic = font.getBoolean("italic");
                }
                if (font.containsKey("bold")) {
                    bold = font.getBoolean("bold");

                }
            }
            if (styleJson.containsKey("underline")) {
                //下划线
                underline = styleJson.getBoolean("underline");
            }
            if (styleJson.containsKey("strike")) {
                //删除线
                strike = styleJson.getBoolean("strike");

            }

        }
        if (StringUtils.isNotBlank(text)) {
            Font font = new Font(bfChinese);
            if (fontSize > 0) {
                font.setSize(fontSize);
            }
            if (underline) {
                font.setStyle(Font.UNDERLINE);
            }
            if (strike) {
                font.setStyle(Font.STRIKETHRU);
            }

            if (italic && bold) {
                font.setStyle(Font.BOLDITALIC);
            } else if (bold) {
                font.setStyle(Font.BOLD);
            } else if (italic) {
                font.setStyle(Font.ITALIC);
            } else {
                font.setStyle(Font.NORMAL);
            }

            if (StringUtils.isNotBlank(color)) {
                font.setColor(toColorFromString(color));
            } else {
                font.setColor(BaseColor.BLACK);
            }
            Phrase elements = new Phrase(text, font);
            pdfCell.setPhrase(elements);
        } else {
            pdfCell.setPhrase(new Phrase(" "));
        }
    }

    /**
     * 字符串转换成Color对象
     *
     * @param colorStr 16进制颜色字符串
     * @return Color对象
     */
    public static BaseColor toColorFromString(String colorStr) {
        if (colorStr.length() < 7) {
            return BaseColor.BLACK;
        }
        int[] rgb = new int[3];
        rgb[0] = Integer.valueOf(colorStr.substring(1, 3), 16);
        rgb[1] = Integer.valueOf(colorStr.substring(3, 5), 16);
        rgb[2] = Integer.valueOf(colorStr.substring(5, 7), 16);
        return new BaseColor(rgb[0], rgb[1], rgb[2]);
    }

    /**
     * 获取表格边框宽度
     * thin      薄
     * medium    中等的
     * thick     厚的
     * dotted    星罗棋布的   暂未处理
     * dashed    虚线  暂未处理
     *
     * @param type
     * @return
     */
    public static float getBorderWidth(String type) {
        if ("thin".equals(type)) {
            return 0.5f;
        }
        if ("medium".equals(type)) {
            return 1f;
        }
        if ("thick".equals(type)) {
            return 1.5f;
        }
        if ("dotted".equals(type)) {
            return 1f;
        }
        if ("dashed".equals(type)) {
            return 1f;
        }
        return 0f;
    }

    /**
     * 创建空的不带边框的单元格
     *
     * @return
     */
    public static PdfPCell createEmptyCell(Integer height) {
        PdfPCell pdfCell = new PdfPCell();
        //不包含边框，默认全部隐藏
        pdfCell.disableBorderSide(Rectangle.LISTITEM);
        pdfCell.setFixedHeight(height);
        pdfCell.setPhrase(new Phrase(" "));
        return pdfCell;
    }

    /**
     * 创建图片demo
     *
     * @return
     */
    public static PdfPCell createImageCell(JSONObject jsonObject, PdfPCell pdfCell) {
        if (null != jsonObject && jsonObject.size() > 0) {
            //二维码条形码设置
            String type = jsonObject.getString("type");
            String content = jsonObject.getString("content");
            Integer codeHeight = jsonObject.getInteger("height");
            Integer codeWidth = jsonObject.getInteger("width");
            BufferedImage image;
            if ("QRCode".equals(type)) {
                image = QrCodeOrBarCodeUtil.createImageQRCode(content, null, codeWidth, codeHeight);
            } else {
                image = QrCodeOrBarCodeUtil.createImageBar(content, codeWidth, codeHeight);
            }
            //新建流
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            Image instance;
            try {
                //利用ImageIO类提供的write方法，将bi以jpg图片的数据模式写入流。
                ImageIO.write(image, "jpg", os);
                instance = Image.getInstance(os.toByteArray());
            } catch (IOException | BadElementException e) {
                throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
            } finally {
                try {
                    os.close();
                } catch (IOException e) {
                    throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage());
                }
            }
            pdfCell.setImage(instance);
        }

        return pdfCell;
    }

    /**
     * 单元格内容位置
     *
     * @param align
     * @return
     */
    public static int getHorizontalAlignment(String align) {
        if ("rigth".equals(align)) {
            return Element.ALIGN_RIGHT;
        } else if ("left".equals(align)) {
            return Element.ALIGN_LEFT;
        } else {
            return Element.ALIGN_CENTER;
        }
    }

    public static int getVerticalAlignment(String valign) {
        if ("top".equals(valign)) {
            return Element.ALIGN_TOP;
        } else if ("bottom".equals(valign)) {
            return Element.ALIGN_BOTTOM;
        } else {
            return Element.ALIGN_MIDDLE;
        }
    }
}
